let x = a + b
let x = @attr (a + b)
let x = @attr (@attr a + @attr b)
let x = a && b + c
let x = (a && b) + c
let x = a && b || c 

let x = (a && b) + (c && d)

while (continuePrefix.contents && aPrefixLen.contents && bPrefixLen.contents && foobarLen.contents) {
  ()
}

// uncurried attribute shouldn't result in parens
while (
  rbt.compare(. Js.Array2.unsafe_get(old, oldIter.contents), node.value) < 0
) {
  ()
}

// unary expr as child of binary expr doesn't need parens
let x = !filePath.includes(allMlSuffixesCategory) &&
  !filePath.endsWith(allScriptDirectoriesCategory)

let name = names[0] ++ names[1]
let name = user["firstName"] ++ user["lastName"]

let x = foo ++ bar
let x = foo != bar
let x = foo !== bar

let x = foo ++ bar
let x = 1 + 1
let x = (a => a + 1) + (b => b + 2)
let x = -1 + -1
let x = switch z { | Red => 1 }->switch y { | Blue => 2 }
let x = try z catch { | Exit => 1 }->try y catch { | Blue => 2 }
let x = if true { 1 } else { 2 } + if false { 2 } else { 3 }
let x = for i in 0 to 10 { () }->for i in 0 to 10 { () }

let x = (a, b) + (b, c)
let x = Vec3(a, b, c) + Vec4(a, b, c, d)
let x = {x: 1, y: 2} + {x: 2, y :3}
let x = user.firstName ++ user.lastName
let x = x.left = value->x.right = value
let x = (x.left = value)->x.right = value
let x = (x.left = value)->(x.right = value)
let () = (x.left = value)->logMutation
let () = x.left = value->logMutation
let () = x.left = (value->process)->x.right = value->process
let () = (x: int)->(print_int: int => unit)

x + y / z
x / y + z
x % y * z
x ^^^ y + z
x &&& y + z
x ||| y + z
x << y + z
x >> y + z
x >>> y + z
100 * x / total
2 / 3 * 10 / 2 + 2
let rotateX = ((range / rect.height) * refY - range / 2) * getXMultiplication(rect.width)
let rotateY = ((range / rect.width) * refX - range / 2) * getYMultiplication(rect.width)

let x = longIdentifier + longIdentifier + longIdentifier;
let x = longIdentifier + longIdentifier + longIdentifier + longIdentifier - longIdentifier + longIdentifier;
let x = longIdentifier + longIdentifier * longIdentifier + longIdentifier - longIdentifier + longIdentifier;
let x = longIdentifier + longIdentifier * longIdentifier * longIdentifier / longIdentifier + longIdentifier;

let x = longIdentifier && longIdentifier && longIdentifier && longIdentifier && longIdentifier && longIdentifier;
let x = longIdentifier && longIdentifier || longIdentifier && longIdentifier || longIdentifier && longIdentifier;

// exponentiation is right associative
let x = 2. ** 3. ** 2.
let x = (2. ** 3.) ** 2.
let x = 2. ** (3. ** 2.)

if (
  successorParent.color === Black &&
    (sibling === None ||
      (siblingNN.color === Black &&
      siblingNN.left === None ||
        (siblingNN.left->castNotOption).color === Black &&
      (siblingNN.right === None ||
        (siblingNN.right->castNotOption).color === Black)))
) {
  if sibling !== None {
    siblingNN.color = Red
  }
  successorRef.contents = successorParent
}

let truth = longEqualityExpression.someRecordField ==
wowThisDoesHaveToBePrettyLong.someRecordField &&
  longEqualityExpression.someRecordField ==
  wowThisDoesHaveToBePrettyLong.someRecordField

while (
  continuePrefix.contents &&
  aPrefixLen.contents <= aLen &&
  bPrefixLen.contents <= bLen
) {
  let nextNonwhiteA = nextNonWhiteChar(aStr, 1, aPrefixLen.contents - 1)
  let nextNonwhiteB = nextNonWhiteChar(bStr, 1, bPrefixLen.contents - 1)
  ()
}
let () = {
  let () = sideEffect()
  if (
    (isLeft(successor) && sibling.right === None) ||
      ((sibling.right->castNotOption).color === Black &&
      sibling.left !== None &&
      (sibling.left->castNotOption).color === Red)
  ) {
    sibling.color = Red
    sibling.left->castNotOption.color = Black
    rotateRight(rbt, sibling)
  }
  if (
    sibling !== None && (sibling->castNotOption).color === Black
  ) {
    let sibling = sibling->castNotOption
    if (
      isLeft(successor) &&
      sibling.right === None ||
        (sibling.right->castNotOption).color === Black &&
      sibling.left !== None &&
      (sibling.left->castNotOption).color === Red
    ) {
      sibling.color = Red
      sibling.left->castNotOption.color = Black
      rotateRight(rbt, sibling)
    } else if (
      !isLeft(successor) &&
      sibling.left === None ||
        (sibling.left->castNotOption).color === Black &&
      sibling.right !== None &&
      (sibling.right->castNotOption).color === Red
    ) {
      sibling.color = Red
      sibling.right->castNotOption.color = Black
      rotateLeft(rbt, sibling)
    }
    break.contents = true
  } else {
    let sibling = siblingOf(successor)
    let sibling = sibling->castNotOption
    sibling.color = successorParent.color
    if isLeft(successor) {
      sibling.right->castNotOption.color = Black
      rotateRight(rbt, successorParent)
    } else {
      sibling.left->castNotOption.color = Black
      rotateLeft(rbt, successorParent)
    }
  }
}

let x = a && (b || c)
let x = a && (b || c) && d
let x = a && b + c
let x = a && b + c && d

let x = a && @attr b && c
let x = @attr a && @attr b && @attr c
let x = a && @attr (b && c)
let x = a && @attr (b && c) && @attr (d && e)

let x = a && @attr (x->f(g))
let x = a && @attr (x->f(g)) && @attr (y->f(h))

let x = a && a.b
let x = a && x.y && g.h
let x = a && true
let x = a && true && true
let x = a && {let a = true; let b = true; a || b}
let x = a && {let a = true; let b = true; a || b} && {let a = true; let b = true; a || b}

let x = a && x => x->Js.log
let x = a && (x => x->Js.log) && x => x->Js.log

let x = a && !b
let x = a && !b && !c

let x = a && f(b)
let x = a && f(b) && f(c)

let x = a && f(. b)
let x = a && f(. b) && f(. c)

let x = a && x->f(g)
let x = a && x->f(g) && y->f(h)

let x = a && switch color {
  | Blue => "blue"
  | Red => "red"
}
let x = a && switch color {
  | Blue => "blue"
  | Red => "red"
} && switch color {
  | Blue => "blue"
  | Red => "red"
}

let x = a && try unsafe() catch {
  | Error => ()
}

let x = a && try unsafe() catch {
  | Error => ()
} && try unsafe() catch {
  | Error => ()
}

let x = a && (a, b)
let x = a && (a, b) && (c, d)

let x = a && Foo(x, y)
let x = a && Foo(x, y) && Foo(x, y, z)

let x = a && {x: 1, y: 2}
let x = a && {x: 1, y: 2} && {x: 3, y: 3}

let x = a && b.c
let x = a && b.c && d.e

let x = a && row.id = 1
let x = a && (row.id = 1) && row2.id = 3

let x = a && [a, b]
let x = a && [a, b] && [c, d]

let x = a && if true { true } else { false }
let x = a && if true { true } else { false } && if false { false } else { true}

let x = a && {sideEffect(); do()}
let x = a && {sideEffect(); do()} && {sideEffect(); do()}

let x = a && while true { do() }
let x = a && while true { do() } && while true { do() }

let x = a && for i in 0 to 10 { true }
let x = a && for i in 0 to 10 { true } && for i in 0 to 10 { false }

let x = a && (truth: bool)
let x = a && (truth: bool) && (otherTruth: bool)

let x = a && {module L = Log; L.log()}
let x = a && {module L = Log; L.log()} && {module L = Log; L.log()}

let x = a && {exception Exit; throw(Exit)}
let x = a && {exception Exit; throw(Exit)} && {exception Exit; throw(Exit)}

let x = a && assert(false)
let x = a && assert(false) && assert(true)

let x = a && {open React; killPerform()}
let x = a && {open React; killPerform()} && {open Dom; regainPerform()}

let x = a && %raw("true")
let x = a && %raw("true") && %raw("false")

let x = a && module(Foo)
let x = a && module(Foo) && module(Bar)

let x = a && module(Foo: Bool)
let x = a && module(Foo: Bool) && module(Bar: Bool)

let x = a && truths[0]
let x = a && truths[0] && truths[1]

let () = node.left := value->process->node.right = value->process
let () = (node.left := value->process)->node.right = value->process

let x = (true ? 0 : 1) + (false ? 1 : 0)
let x = (true ? 0 : 1) + (false ? 1 : 0) +  (false ? 1 : 0)

while (
  oldIter.contents < oldLen &&
    rbt.compare(.
      Js.Array2.unsafe_get(old, oldIter.contents),
      node.value,
    )
) {
  disappear(. Js.Array2.unsafe_get(old, oldIter.contents))
  oldIter.contents = oldIter.contents + 1
}

 while (
    oldIter.contents < oldLen &&
      rbt.compare(.
        Js.Array2.unsafe_get(old, oldIter.contents),
        node.value,
      ) < 0
  ) {
    disappear(. Js.Array2.unsafe_get(old, oldIter.contents))
    oldIter.contents = oldIter.contents + 1
  }

let x =
  oldIter.contents < oldLen &&
  rbt.compare(Js.Array2.unsafe_get(old, oldIter.contents), node.value) < veryLongIdentifier;

// should be formatted on one line, i.e. NOT break
let fullCircle = 2. *. pi

a + b + c
a + b - c
a < b < c

a + (b + c)
a + (b + (c + d))
a + (b - (c - d))
a < (b < c)
a < (b < (c < d))

a || b || c
a || (b || c)
a || (b || (c || d))

a && b && c
a && (b && c)
a && (b && (c && d))

a && b || c
a && (b || c)

x->(y->z)
x->(y->(z->w))
x->(y &&(w && z))
(x->y)->z

(x->y)->z
x->(y->z)
x->(y->(z->w))

let x = "z" ++ (a->f) ++ "x"
let toString = functionArgs => {
  functionArgs == []
    ? ""
    : "<"
      ++ (functionArgs->List.map(argToString)->String.concat(","))
      ++ ">"
}

a->Author.id != (author->Author.id)

// should indent the switch
foo :=
  switch bar.contents {
  | _ => 1
  }

<div> {possibleGradeValues->List.filter(g =>
    g < state.maxGrade
  )->List.map(possibleGradeValue =>
    <option key={possibleGradeValue->string_of_int} value={possibleGradeValue->string_of_int}>
      {possibleGradeValue->string_of_int->str}
    </option>
  )->Array.of_list->ReasonReact.array} </div>

let aggregateTotal = (forecast, ~audienceType) =>
  Js.Nullable.toOption(forecast["audiences"])
  ->Option.flatMap(item =>
    Js.Dict.get(item, audienceType)
  )
  ->Option.map(item => {
    pages: item["reach"]["pages"],
    views: item["reach"]["views"],
    sample: item["reach"]["sample"],
  })

React.useEffect4(
  () => {
    switch (context.library, context.account) {
    | (Some(library), Some(account)) =>
      library.getBalance(. account)
      ->Promise.Js.catch(_ => {Promise.resolved(None)})
      ->Promise.get(newBalance => {
          dispatch(
            LoadAddress(
              account,
              newBalance->Belt.Option.flatMap(balance =>
                Eth.make(balance.toString(.))
              ),
            ),
          )
        })

      None
    | _ => None
    }
  },
  (context.library, context.account, context.chainId, dispatch),
)

@react.component
let make = (~keycap) =>
  <Kbd keycap="Ctrl" /> +
  <Kbd keycap="Shift" /> +
  <Kbd keycap />


<Kbd keycap="Cmd" /> +
<Kbd keycap="Option" /> +
<Kbd keycap="Shift" /> +
<Kbd keycap />

// rescript-lang/syntax/issues/499
(@doesNotRaise [])->Belt.Array.getExn(0)
@doesNotRaise
[]->Belt.Array.getExn(0)
